use std::sync::Arc;

use axum::{
    http::StatusCode,
    routing::{get, get_service},
    AddExtensionLayer, Router,
};
use dotenv::dotenv;
use tower_http::services::ServeDir;

mod config;
mod db;
mod error;
mod handler;
mod html;
mod model;
mod redis;

type Result<T> = std::result::Result<T, error::AppError>;

#[tokio::main]
async fn main() {
    // 初始化日志
    if std::env::var_os("RUST_LOG").is_none() {
        std::env::set_var("RUST_LOG", "blog=debug");
    }
    tracing_subscriber::fmt::init();

    dotenv().ok();
    let cfg = config::Config::from_env().expect("初始化配置失败");
    let pool = cfg
        .pg
        .create_pool(tokio_postgres::NoTls)
        .expect("初始化数据库连接池失败");
    let rdc = ::redis::Client::open(cfg.redis.dsn.as_str()).expect("创建Redis连接失败");

    let admin_router = Router::new().route("/", get(handler::backend::index));

    let app = Router::new()
        .route("/", get(handler::frontend::index))
        .nest("/admin", admin_router)
        .nest(
            &cfg.web.static_path,
            get_service(ServeDir::new(&cfg.web.static_dir)).handle_error(|err| async move {
                (
                    StatusCode::INTERNAL_SERVER_ERROR,
                    format!("处理静态资源出错：{:?}", err),
                )
            }),
        )
        .layer(AddExtensionLayer::new(Arc::new(model::AppState {
            pool,
            rdc,
        })));

    tracing::info!("服务运行于：{}", &cfg.web.addr);

    axum::Server::bind(&cfg.web.addr.parse().unwrap())
        .serve(app.into_make_service())
        .await
        .unwrap();
}
